﻿#region License
/*

	Copyright (C) 2008 Oliver Charles, Daniel Hollander

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
*/
#endregion

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using SlimDX;
using SlimDX.Direct3D9;

namespace Moebius.Rendering.Direct3D9
{
    [StructLayout(LayoutKind.Sequential)]
    struct Vertex
    {
        public Vector3 Position;
        public float Tu;
        public float Tv;

        public static int SizeBytes
        {
            get { return Marshal.SizeOf(typeof(Vertex)); }
        }

        public static VertexFormat Format
        {
            get { return VertexFormat.Position | VertexFormat.Texture1; }
        }

        public Vertex(Vector3 position, float tu, float tv)
        {
            Position = position;
            Tu = tu;
            Tv = tv;
        }
    }

    public class Image : Components.Image, IDisposable
    {
        private Renderer device;
        private int quadCounter;

        private VertexBuffer vertices;
        private IndexBuffer indices;

        public VertexBuffer Vertices
        {
            get { return vertices; }
        }

        internal void Initialize(Renderer renderingDevice)
        {
            if (renderingDevice == null) throw new ArgumentNullException("renderingDevice");

            device = renderingDevice;
        }

        public override void Initialize(int initialQuadCount, float layer)
        {
            base.Initialize(initialQuadCount, layer);

            vertices = new VertexBuffer(device.Direct3DDevice, Vertex.SizeBytes * 4 * initialQuadCount,
                                        Usage.Dynamic | Usage.WriteOnly, Vertex.Format, Pool.Default);

            indices = new IndexBuffer(device.Direct3DDevice, sizeof(short) * 6 * initialQuadCount,
                                      Usage.Dynamic | Usage.WriteOnly, Pool.Default, true);
        }

        public override void AddQuad(RectangleF rectangle, string imageIdentifier)
        {
            RectangleF uvCoords = ImageAtlas.GetUVCoordinates(imageIdentifier);

            Vertex[] rawVerts = {
								   new Vertex(new Vector3(rectangle.Left,	rectangle.Top, Layer), uvCoords.Left, uvCoords.Top),
                                   new Vertex(new Vector3(rectangle.Left,	rectangle.Bottom, Layer), uvCoords.Left, uvCoords.Bottom),
								   new Vertex(new Vector3(rectangle.Right,	rectangle.Top, Layer), uvCoords.Right, uvCoords.Top),
								   new Vertex(new Vector3(rectangle.Right,	rectangle.Bottom, Layer), uvCoords.Right, uvCoords.Bottom)
							   };

            DataStream vertData = Vertices.Lock(quadCounter*4*Vertex.SizeBytes, 4*Vertex.SizeBytes,
                                                LockFlags.NoOverwrite);
            vertData.WriteRange(rawVerts);
            Vertices.Unlock();

            DataStream indexData = indices.Lock(quadCounter*6*sizeof (short), 6*sizeof (short),
                                                LockFlags.NoOverwrite);
            short[] indicesData = new short[]
                {
                    (short)(quadCounter * 4 + 0), (short)(quadCounter * 4 + 2), (short)(quadCounter * 4 + 1),
                    (short)(quadCounter * 4 + 1), (short)(quadCounter * 4 + 2), (short)(quadCounter * 4 + 3)
                };
            indexData.WriteRange(indicesData);
            indices.Unlock();

            quadCounter++;
        }

		internal void Render()
        {
            device.Direct3DDevice.SetStreamSource(0, vertices, 0, Vertex.SizeBytes);
            device.Direct3DDevice.VertexFormat = Vertex.Format;
            device.Direct3DDevice.SetIndices(indices);
            ImageAtlas.Activate();

            device.Direct3DDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, quadCounter * 4,
                                                        0, quadCounter * 2);
        }

		#region IDisposable Implementation
		
		private bool disposed;

		~Image()
		{
			Dispose(false);
		}

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

		protected virtual void Dispose(bool disposing)
        {
			if(!disposed) 
			{
				if(disposing)
				{
					vertices.Dispose();
					indices.Dispose();
				}
				
				disposed = true;
			}
        }

		#endregion
    }
}